#include "StdAfx.h"
#include "ServerChannelCoreImpl.h"
#include "VcServerUtils.h"


rdc_transport::ServerChannelCoreImpl::ServerChannelCoreImpl(std::string& channelName) 
: m_connectionHandle(rdc_transport::OpenChannel(channelName))
, m_hWTSFileHandle(NULL)
, m_terminateEvent(FALSE, FALSE)
{
    rdc_transport::GetChannelFile(m_hWTSFileHandle, m_connectionHandle.get());
}

rdc_transport::ServerChannelCoreImpl::~ServerChannelCoreImpl()
{
    m_terminateEvent.Set();
}

void rdc_transport::ServerChannelCoreImpl::Write(Buffer* pBuffer)
{
    OVERLAPPED ovr = { 0 };
    ATL::CEvent writeEvent(FALSE, FALSE);
    ovr.hEvent = writeEvent.m_h;

    DWORD dwBytesWritten;
    BOOL bRes = ::WriteFile(
        m_hWTSFileHandle, 
        &(pBuffer->at(0)),
        pBuffer->size(), 
        &dwBytesWritten, 
        &ovr);

    if ((bRes == FALSE) && (::GetLastError() == ERROR_IO_PENDING))
    {
        HANDLE hHandles[] = { ovr.hEvent, m_terminateEvent.m_h };

        DWORD dwWait = ::WaitForMultipleObjects(
            sizeof(hHandles) / sizeof(HANDLE),
            hHandles,
            FALSE,
            INFINITE);

        if (dwWait == WAIT_OBJECT_0)
            bRes = ::GetOverlappedResult(m_hWTSFileHandle, &ovr, &dwBytesWritten, FALSE);
        else
            throw std::runtime_error(std::string(__FUNCTION__) + " Error: terminated");
    }

    if (bRes == FALSE)
        throw std::runtime_error(std::string(__FUNCTION__) + " Unexpected Error " + utils::FormatLastError());
}

void rdc_transport::ServerChannelCoreImpl::ReadFile(PCHAR pBuffer, DWORD dwInSize, PDWORD pdwOutSize)
{
    OVERLAPPED ovr = { 0 };
    CEvent readEvent(FALSE, FALSE);
    ovr.hEvent = readEvent.m_h;

    BOOL bRes = ::ReadFile(
        m_hWTSFileHandle,
        pBuffer,
        dwInSize,
        pdwOutSize,
        &ovr);

    if ((bRes == FALSE) && (::GetLastError() == ERROR_IO_PENDING))
    {
        HANDLE hHandles[] = { ovr.hEvent, m_terminateEvent.m_h };

        DWORD dwWait = ::WaitForMultipleObjects(
            sizeof(hHandles) / sizeof(HANDLE),
            hHandles,
            FALSE,
            INFINITE);

        if (dwWait == WAIT_OBJECT_0)
            bRes = ::GetOverlappedResult(m_hWTSFileHandle, &ovr, pdwOutSize, FALSE);
        else if (dwWait == WAIT_OBJECT_0 +1)
            throw termination_notification(std::string(__FUNCTION__) + " Error: Terminated");
        else
            throw std::runtime_error(std::string(__FUNCTION__) + " Error: exception occurred");
    }

    if (bRes == FALSE || (*pdwOutSize == 0))
        throw std::runtime_error(std::string(__FUNCTION__) + "Unexpected error" + utils::FormatLastError());
}

void rdc_transport::ServerChannelCoreImpl::Terminate()
{
    m_terminateEvent.Set();
}